--[[
-- Author:      feilong
-- DateTime:    2020-10-10 17:19:33
-- Description: 
    1监听客户端数据
    2根据消息id来区分这个消息由那个类型的节点来处理

--]]


local skynet = require "skynet"
local proto = require "proto"



local table_insert = table.insert



-- 每个客户端 每分钟 平均数量
local SEC_PACK_COUNT = 30
local CHECK_INTERVAL = 5*60
local ACCOUNT_MSG_RANGE_MIN = 80000
local ACCOUNT_MSG_RANGE_MAX = 80099
local PACKED_PROXY_IP_SIZE = 4

local MessageHandler = class("MessageHandler")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function MessageHandler:ctor()

    self.game_session_counter = 0 --客户端唯一标识
    self.client_sessions = {} --
    self.game_session_fds = {}
    self.client_pack = new("client_pack")
    self.server_config = dofile(skynet.getenv("server_config"))
    --socket状态消息
    self.socket_handler = {}

	self:register()	
end

--注册本服务里的消息
function MessageHandler:register()    
    self.socket_handler.open = handler(self,self.openSocket)
    self.socket_handler.close = handler(self,self.closeSocket)
    self.socket_handler.error = handler(self,self.errorSocket)
    self.socket_handler.warning = handler(self,self.warningSocket)
    self.socket_handler.data = handler(self,self.dataSocket) 

    self.message_dispatch = g.MsgDis()
    self.message_dispatch:register("start", handler(self, self.start))
    self.message_dispatch:register("socket", handler(self, self.clientData))
    self.message_dispatch:register('send_to_user', handler(self, self.sendToUser)) --
end

function MessageHandler:createSession()
    if self.game_session_counter >= (1 << 31) then
        print('self.game_session_counter has been overflow ',self.game_session_counter)
        self.game_session_counter = 0
    end
    local node_info = self.server_config.node_info
    local server_id = node_info.id
    local game_session = server_id << 31 | self.game_session_counter
    self.game_session_counter = self.game_session_counter + 1
    return game_session
end

--watchdog全盘托管所有的网络流量，根据规则打包成内部协议再转发给后端
function MessageHandler:openSocket(fd, addr)
    g.Log():error("New client from : " , fd, addr)

    -- skynet.call(".gate", 'lua', 'accept', fd)
    g.Message():callService(".gate", "accept", fd)
    local ipaddr = addr:sub(1,addr:find(':')-1)
    local game_session = self:createSession()
    print('open new session',fd,game_session)
    local curr_time = skynet.now()
    self.client_sessions[fd] = {
        s = game_session,
        p = curr_time,  --last received time
        ip = ipaddr,
        count = 0,
        last_check_time = curr_time,
        total_traffic = 0,
    }
    self.game_session_fds[game_session] = fd
end


function MessageHandler:closeAgent(fd)
    local client = self.client_sessions[fd]
    if client then
        local game_session = client.s
        assert(self.game_session_fds[game_session])
        self.client_sessions[fd] = nil
        self.game_session_fds[game_session] = nil
        skynet.call(".gate", "lua", "kick", fd)
        
        --通知与之关联的节点关闭连接
        -- if client.uid and client.observers then
        --     for dest,target in pairs(client.observers) do
        --         R().dest(dest):send(target,'close',client.uid,game_session,'closed')
        --     end
        -- end

        g.Log():debug('close socket',fd,game_session,client.uid,client.observers)
    end
end

function MessageHandler:closeSocket(fd)
    print("socket close",fd)
    self:closeAgent(fd)
end

function MessageHandler:errorSocket(fd, msg)
    print("socket error",fd, msg)
    self:closeAgent(fd)
end

function MessageHandler:warningSocket(fd, size)
    -- size K bytes havn't send out in fd
    print("socket warning", fd, size)
end


--连接的合法性检查
function MessageHandler:checkClientRequest(c,msgid,server_name)
    if c.uid then
        --已经有uid了则放行
        return true
    end

    --该用户目前仍没有uid，则需要去accountsvr取得uid
    if server_name ~= 'accountsvr' or 
        msgid <  ACCOUNT_MSG_RANGE_MIN or 
        msgid > ACCOUNT_MSG_RANGE_MAX then
        return false
    end

    return true
end

--客户端的发包量记录
function MessageHandler:fluxMonitor(client, sz, curr_time)
    
    client.count = client.count + 1
    client.total_traffic = client.total_traffic + sz

    if curr_time - CHECK_INTERVAL*100 > client.last_check_time then

        local average_count = math.floor(client.count / CHECK_INTERVAL)
        if average_count > SEC_PACK_COUNT then
            -- billlog({op="pack_count_warning",uid = client.uid,average_count = average_count,pack_count = client.count,
            -- ip = client.ip,period_traffic_KB = client.total_traffic / 1024})
        end

        client.count = 0
        client.total_traffic = 0
        client.last_check_time = curr_time
    end
end

--接收到客户端消息并处理
function MessageHandler:dataSocket(fd, msg, sz)

    if not sz then
        sz = #msg
    end
    g.Log():error("________dataSocket_____",  sz, skynet.genid())
    local msg_id, msg_name, msg_data = self.client_pack:unpack(msg,sz)
    g.Log():error("____1111____dataSocket_____",  msg_data, skynet.now(), skynet.time())
    local client = assert(self.client_sessions[fd])
    local curr_time = skynet.now()
    client.p = curr_time
    self:fluxMonitor(client, sz, curr_time)
    local server_type = proto.getServerTypeById(msg_id)
    local node = g.Message():callManager("get_server", server_type)
    local uid = client.uid
    print("MessageHandler:dataSocket uid", uid, server_type)
    if server_type == "accountserver" then 
        --发到指定节点
        g.Message():sendNodeManager(node.name, msg_name, client.s, msg_data)
    elseif server_type == "hallserver" and uid and uid > 0 then 
        g.Message():sendNodeManager(node.name, uid, client, msg_name, msg_data)
    elseif server_type == "gameserver" then 

    end






    -- --发个包回去测试
    -- local REQ_VERIFY = {
    --     uid = 1,
    --     key_token = "22222",
    --     package_channel = "ss",
    --     os_system = "window",
    -- }    
    -- self.client_pack:send(fd, "account.REQ_VERIFY", REQ_VERIFY) 
    




    -- if packed_proxy_ip and not client.real_ip then
    --     local real_ip = string.unpack('>I4',packed_proxy_ip)
    --     client.real_ip = real_ip
    --     client.ip = real_ip
    -- end

    --根据消息id取一个相应类型的节点
    -- local server_name,server_id = server_def.get_server_info(dest)
    -- g.Log():debug('got data from client',fd,dest,msgid,sz,client.uid,server_name)
    -- if not self:checkClientRequest(client,msgid,server_name) then
    --     g.Log():error(fd,'illegal destination or msgid',dest,msgid)
    --     --断开链接吧
    --     self:closeAgent(fd)
    --     return
    -- end

    -- if server_name == 'hallsvr' then
    --     --hallsvr由不得客户端自己选择id
    --     local uid = assert(client.uid)
    --     --proxypack.modify_dest_to_uid(uid,msg,sz)
    --     R().hallsvr({key=uid}):send('.msg_handler','data',client.s,skynet.tostring(msg,sz),client.uid,client.ip,client.account_id)
    -- elseif server_name == 'tablesvr' then
    --     local uid = assert(client.uid)
    --     --proxypack.modify_dest_to_uid(uid,msg,sz)
    --     R().dest(dest):send('.msg_handler','data',client.s,skynet.tostring(msg,sz),client.uid,client.ip)
    -- elseif server_name == 'accountsvr' then
    --     R().accountsvr({rand=true}):send('.msg_handler','data',client.s,skynet.tostring(msg,sz),client.ip)
    -- else
    --     --玩家除了既定的一些服务器之外，没法主动选择其它服务器
    --     g.Log():error(fd,'illegal destination',dest,msgid,server_name,server_id)
    --     self:closeAgent(fd)
    --     return
    -- end




end



---------------------------------------------------------
-- CMD
---------------------------------------------------------
function MessageHandler:start()

  
end

function MessageHandler:clientData(cmd, fd, ... )
    print("__________", cmd, fd, ...)
    local func = self.socket_handler[cmd]   
    if func then
        return func(fd, ...)
    end
end

--服务端发消息给用户
function MessageHandler:sendToUser(session, msg_name, msg_data, account_id)
    local fd = self.game_session_fds[session]
    local err_code = msg_data.result
    local err_des = g.ErrorDes(err_code)
    msg_data.description = err_des
    print("____sendToUser_______",session, msg_name, msg_data, account_id)
    local client = self.client_sessions[fd]
    local uid = msg_data.uid 
    if not client.uid and uid and uid ~= 0 and not client.account_id and account_id then 
        client.uid = uid
        client.account_id = account_id
    end
    self.client_pack:send(fd, msg_name, msg_data)
end




return MessageHandler